/**********************************************************************
* Filename: Campeonato.java
* Created: 2012/04/20
* @author Fernando Brito e Abreu
**********************************************************************/
package org.luis_dores.copaPaises.businessLayer;

import java.util.Set;
import java.util.HashSet;

public class Campeonato
{
	public static Set<Campeonato> allInstances = new HashSet<Campeonato>();
	
	private CalendarDate data_inicio;
	private FaseCampeonato fase_actual;
	private TipoCampeonato genero;
	private String nome;
	private boolean status;
	
	/**********************************************************************
	* Default constructor
	**********************************************************************/
	public Campeonato()
	{
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Parameterized constructor
	* @param data_inicio the data_inicio to initialize
	* @param fase_actual the fase_actual to initialize
	* @param genero the genero to initialize
	* @param nome the nome to initialize
	* @param status the status to initialize
	**********************************************************************/
	public Campeonato(CalendarDate data_inicio, FaseCampeonato fase_actual, TipoCampeonato genero, String nome, boolean status)
	{
		this.data_inicio = data_inicio;
		this.fase_actual = fase_actual;
		this.genero = genero;
		this.nome = nome;
		this.status = status;
		allInstances.add(this);
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the data_inicio of the campeonato
	**********************************************************************/
	public CalendarDate data_inicio()
	{
		return data_inicio;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param data_inicio the data_inicio to set
	**********************************************************************/
	public void setData_inicio(CalendarDate data_inicio)
	{
		this.data_inicio = data_inicio;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the fase_actual of the campeonato
	**********************************************************************/
	public FaseCampeonato fase_actual()
	{
		return fase_actual;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param fase_actual the fase_actual to set
	**********************************************************************/
	public void setFase_actual(FaseCampeonato fase_actual)
	{
		this.fase_actual = fase_actual;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the genero of the campeonato
	**********************************************************************/
	public TipoCampeonato genero()
	{
		return genero;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param genero the genero to set
	**********************************************************************/
	public void setGenero(TipoCampeonato genero)
	{
		this.genero = genero;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the nome of the campeonato
	**********************************************************************/
	public String nome()
	{
		return nome;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param nome the nome to set
	**********************************************************************/
	public void setNome(String nome)
	{
		this.nome = nome;
	}
	
	/**********************************************************************
	* Standard attribute getter
	* @return the status of the campeonato
	**********************************************************************/
	public boolean status()
	{
		return status;
	}
	
	/**********************************************************************
	* Standard attribute setter
	* @param status the status to set
	**********************************************************************/
	public void setStatus(boolean status)
	{
		this.status = status;
	}
	
	/**********************************************************************
	* ONE2MANY getter for Campeonato[1] <-> Grupo[*]
	* @return the grupos of the campeonato
	**********************************************************************/
	public Set<Grupo> grupos()
	{
		Set<Grupo> result = new HashSet<Grupo>();
		for (Grupo x : Grupo.allInstances)
			if (x.campeonato()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* ONE2MANY setter for Campeonato[1] <-> Grupo[*]
	* @param grupos the grupos to set
	**********************************************************************/
	public void setGrupos(Set<Grupo> grupos)
	{
		for (Grupo x : grupos)
			x.setCampeonato(this);
	}
	
	/**********************************************************************
	* MEMBER2ASSOCIATIVE getter for Campeonato[*] <-> Participacao[2..*]
	* @return the participacao of the participado
	**********************************************************************/
	public Set<Participacao> participacao()
	{
		Set<Participacao> result = new HashSet<Participacao>();
		for (Participacao x : Participacao.allInstances)
			if (x.participado()  ==  this)
				result.add(x);
		return result;
	}
	
	/**********************************************************************
	* MEMBER2ASSOCIATIVE setter for Campeonato[*] <-> Participacao[2..*]
	* @param participacao the participacao to set
	**********************************************************************/
	public void setParticipacao(Set<Participacao> participacao)
	{
		for (Participacao x : participacao)
			x.setParticipado(this);
	}
	
	/**********************************************************************
	* MEMBER2MEMBER getter for Campeonato[*] <-> Pais[2..*]
	* @return the participante of the participado
	**********************************************************************/
	public Set<Pais> participante()
	{
		Set<Pais> result = new HashSet<Pais>();
		for (Participacao x : Participacao.allInstances)
			if (x.participado()  ==  this)
				result.add(x.participante());
		return result;
	}
	
	/**********************************************************************
	* MEMBER2MEMBER setter for Campeonato[*] <-> Pais[2..*]
	* @param participante the participante to set
	**********************************************************************/
	public void setParticipante(Set<Pais> participante)
	{
		for (Pais t : participante)
			for (Participacao x: Participacao.allInstances)
				if (x.participado() == this)
					x.setParticipante(t);
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public int MaxIdadesJogadores()
	{
		int idade_maxima = 0; 	
		for(Participacao p : Participacao.allInstances)
			for(Jogador j : p.plantel())
			if(j.data_nascimento().yearsSince(data_inicio) > idade_maxima) {
				idade_maxima = j.data_nascimento().yearsSince(data_inicio);
			}
			
		
		return idade_maxima;
//		return self.participacao->collectNested($e : Participacao | $e.plantel)->flatten->iterate(j : Jogador; acc : Bag(Integer) = Bag {} | acc->including(self.data_inicio.yearsSince(j.data_nascimento)))->max
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public int MediaIdadesJogadores()
	{
		int media = 0;
		int soma = 0;
		int totaldejogadores = 0;
		for(Participacao p : Participacao.allInstances){
			for(Jogador j : p.plantel()){
				totaldejogadores =p.plantel().size();
				soma += j.data_nascimento().yearsSince(data_inicio);
			}
		}
		media = soma/totaldejogadores;
		return media;
//		return (self.participacao->collectNested($e : Participacao | $e.plantel)->flatten->iterate(j : Jogador; acc : Bag(Integer) = Bag {} | acc->including(self.data_inicio.yearsSince(j.data_nascimento)))->sum / self.participacao->collectNested($e : Participacao | $e.plantel)->flatten->size)
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public int MinIdadesJogadores()
	{
			int idade_minima = 0; 	
			for(Participacao p : Participacao.allInstances)
				for(Jogador j : p.plantel())
				if(j.data_nascimento().yearsSince(data_inicio) < idade_minima) {
					idade_minima = j.data_nascimento().yearsSince(data_inicio);
				}
				
			
			return idade_minima;
		//	return self.participacao->collectNested($e : Participacao | $e.plantel)->flatten->iterate(j : Jogador; acc : Bag(Integer) = Bag {} | acc->including(self.data_inicio.yearsSince(j.data_nascimento)))->min
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public int NumeroCartoesAmarelos()
	{
		int numero_amarelos = 0;
		for(Participacao p : Participacao.allInstances)
			for(Jogador j : p.plantel())
				for(Membro b : j.membro())
					for(Cartao c : b.cartoes())
						if(c.tipo().equals("Amarelo"))
					++numero_amarelos; 

		
		return numero_amarelos;
		
//		return self.participacao->collectNested($e : Participacao | $e.plantel)->flatten->collectNested($e : Jogador | $e.membro)->flatten->collectNested($e : Membro | $e.cartoes)->flatten->select(c : Cartao | (c.tipo = TipoCartao::Amarelo))->size
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public int NumeroCartoesVermelhos()
	{
		int numero_vermelhos = 0;
		for(Participacao p : Participacao.allInstances)
			for(Jogador j : p.plantel())
				for(Membro b : j.membro())
					for(Cartao c : b.cartoes())
						if(c.tipo().equals("Vermelho"))
					++numero_vermelhos; 


		return numero_vermelhos;
		
		//	return self.participacao->collectNested($e : Participacao | $e.plantel)->flatten->collectNested($e : Jogador | $e.membro)->flatten->collectNested($e : Membro | $e.cartoes)->flatten->select(c : Cartao | (c.tipo = TipoCartao::Vermelho))->size

	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param pais the pais to set
	**********************************************************************/
	public Set<Participante> ParticipantesPais(Pais pais)
	{
		Set<Participante> participantes = new HashSet<Participante>();
			for(Pais p : Pais.allInstances)
				for(Participante c : p.nacionais())
					if(c.nacionalidade() == pais)
						participantes.add(c);
			return participantes;
						

		//	return self.participante->select(p : Pais | (p = pais))->collectNested($e : Pais | $e.nacionais)->flatten->asSet
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param data_jogo the data_jogo to set
	* @param hora_jogo the hora_jogo to set
	**********************************************************************/
	public void criaFinal(String data_jogo, String hora_jogo)
	{
		
		
		//	self.fase_actual := FaseCampeonato::Final;
		//	 Vencedores := self.grupos->select(g : Grupo | (g.fase = FaseCampeonato::MeiasFinais))->collectNested($e : Grupo | $e.jogos)->flatten->asOrderedSet->collectNested($e : Jogo | $e.PaisVencedor());
		//	 Estadio_MaiorLotacao := self.participante->collectNested($e : Pais | $e.cidades)->flatten->collectNested($e : Cidade | $e.estadios)->flatten->select(e : Estadio | (e.lotacao = self.participante->collectNested($e : Pais | $e.cidades)->flatten->collectNested($e : Cidade | $e.estadios)->flatten->collectNested($e : Estadio | $e.lotacao)->max))->asSequence->first;
		//	 Grupos := self.grupos->select(g : Grupo | (g.fase = FaseCampeonato::Final))->asOrderedSet->first;
		//	 jogo1 := new Jogo('Jogo_final');
		//	 jogo1.inicializa(data_jogo, hora_jogo, Vencedores->at(1), Vencedores->at(2), Estadio_MaiorLotacao, Grupos);
		//	 for eq in self.grupos->select(g : Grupo | (g.fase = FaseCampeonato::Final))->collectNested($e : Grupo | $e.jogos)->flatten->collectNested($e : Jogo | $e.equipa)->flatten->asSet do eq.IniciaMembros() end;
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param data_jogo1 the data_jogo1 to set
	* @param hora_jogo1 the hora_jogo1 to set
	* @param data_jogo2 the data_jogo2 to set
	* @param hora_jogo2 the hora_jogo2 to set
	**********************************************************************/
	public void criaMeiasFinais(String data_jogo1, String hora_jogo1, String data_jogo2, String hora_jogo2)
	{
		//	TODO
		//	self.fase_actual := FaseCampeonato::Final;
		//	 Vencedores := self.grupos->select(g : Grupo | (g.fase = FaseCampeonato::QuartosFinal))->collectNested($e : Grupo | $e.jogos)->flatten->asOrderedSet->collectNested($e : Jogo | $e.PaisVencedor());
		//	 Estadio_MaiorLotacao := self.participante->collectNested($e : Pais | $e.cidades)->flatten->collectNested($e : Cidade | $e.estadios)->flatten->select(e : Estadio | (e.lotacao = self.participante->collectNested($e : Pais | $e.cidades)->flatten->collectNested($e : Cidade | $e.estadios)->flatten->collectNested($e : Estadio | $e.lotacao)->max))->asSequence->first;
		//	 Grupos := self.grupos->select(g : Grupo | (g.fase = FaseCampeonato::MeiasFinais))->asOrderedSet->first;
		//	 jogo1 := new Jogo('Jogo1_meias');
		//	 jogo1.inicializa(data_jogo1, hora_jogo1, Vencedores->at(1), Vencedores->at(3), Estadio_MaiorLotacao, Grupos);
		//	 jogo2 := new Jogo('Jogo2_meias');
		//	 jogo2.inicializa(data_jogo2, hora_jogo2, Vencedores->at(2), Vencedores->at(4), Estadio_MaiorLotacao, Grupos);
		//	 for eq in self.grupos->select(g : Grupo | (g.fase = FaseCampeonato::MeiasFinais))->collectNested($e : Grupo | $e.jogos)->flatten->collectNested($e : Jogo | $e.equipa)->flatten->asSet do eq.IniciaMembros() end;
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public void criaMembrosEquipas()
	{
		//	TODO
		//	for eq in self.grupos->collectNested($e : Grupo | $e.jogos)->flatten->collectNested($e : Jogo | $e.equipa)->flatten->asSet do eq.IniciaMembros() end;
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public void criaQuartosFinal()
	{
			this.fase_actual = FaseCampeonato.QuartosFinal;
		//	self.fase_actual := FaseCampeonato::QuartosFinal;
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	**********************************************************************/
	public void finish()
	{
		
		this.status = false;
		//	self.status := false;
	}
	
	/**********************************************************************
	* User-defined operation specified in SOIL/OCL
	* @param nome the nome to set
	* @param genero the genero to set
	* @param paises the paises to set
	* @param grupos the grupos to set
	* @param data the data to set
	**********************************************************************/
	public void inicializa(String nome, TipoCampeonato genero, String paises, String grupos, CalendarDate data)
	{
		
		this.nome = nome;
		this.genero = genero;
		this.status = true;
		this.data_inicio = data;
		this.fase_actual = FaseCampeonato.Grupos;
		//	self.nome := nome;
		//	 self.genero := genero;
		//	 self.status := true;
		//	 self.fase_actual := FaseCampeonato::Grupos;
		//	 self.data_inicio := data;	
		//	 for p in paises do participacao := new Participacao(((p + '_') + self.nome)) between (new Pais(p),self);
		//	 participacao.organizador := false;
		//	 treinador := new Treinador(('Treinador_' + p));
		//	 insert (treinador,participacao) into Treinador_Participacao end;
		//	 for g in grupos do insert (self,new Grupo(g)) into Campeonato_Grupo end;
	}
	
	/* (non-Javadoc)
	* @see java.lang.Object#toString()
	*/
	@Override
	/**********************************************************************
	* Object serializer
	**********************************************************************/
	public String toString()
	{
		return "Campeonato [data_inicio=" + data_inicio + ", fase_actual=" + fase_actual + ", genero=" + genero + ", nome=" + nome + ", status=" + status + "]\n";
	}
	
}
